#pragma once

// C++ Standard Library and System Headers
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <thread>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <cassert>
#include <fstream>
#include <mutex>
#include <atomic>
#include <unordered_map>
#include <condition_variable>
#include <functional>
#include <cstdio>
#include <charconv>
#include <cstring>

namespace senlog
{
    // Forward Declarations and Type Aliases
    class LogLevel;
    struct LogMsg;
    using LogBuffer = std::vector<char>;

    class LogLevel
    {
    public:
        enum class value
        {
            UNKNOW = 0,
            DEBUG,
            INFO,
            WARN,
            ERROR,
            FATAL,
            OFF
        };
        static const char *tostring(LogLevel::value level)
        {
            switch (level)
            {
            case LogLevel::value::DEBUG:
                return "DEBUG";
            case LogLevel::value::INFO:
                return "INFO";
            case LogLevel::value::WARN:
                return "WARN";
            case LogLevel::value::ERROR:
                return "ERROR";
            case LogLevel::value::FATAL:
                return "FATAL";
            default:
                return "UNKNOWN";
            }
        }
    };

    namespace util
    {
        class Date
        {
        public:
            static size_t getTime() { return (size_t)time(nullptr); }
        };
        class File
        {
        public:
            static bool exists(const std::string &pathname)
            {
                struct stat st;
                return stat(pathname.c_str(), &st) == 0;
            }
            static std::string path(const std::string &pathname)
            {
                size_t pos = pathname.find_last_of("/\\");
                if (pos == std::string::npos)
                    return ".";
                return pathname.substr(0, pos + 1);
            }
            static void createDirectory(const std::string &pathname)
            {
                if (exists(pathname))
                    return;
                size_t pos = 0, idx = 0;
                while (idx < pathname.size())
                {
                    pos = pathname.find_first_of("/\\", idx);
                    std::string parent_dir = pathname.substr(0, (pos == std::string::npos) ? pathname.size() : pos + 1);
                    if (!parent_dir.empty() && !exists(parent_dir))
                    {
                        mkdir(parent_dir.c_str(), 0777);
                    }
                    if (pos == std::string::npos)
                        break;
                    idx = pos + 1;
                }
            }
        };
    }

    struct LogMsg
    {
        time_t _ctime;
        LogLevel::value _level;
        size_t _line;
        std::thread::id _tid;
        std::string _loggername;
        std::string _filename;
        const char *_payload;
        size_t _payload_len;

        LogMsg(LogLevel::value level, size_t line, const std::string &filename,
               const std::string &loggername, const char *payload, size_t payload_len)
            : _ctime(util::Date::getTime()), _level(level), _line(line),
              _tid(std::this_thread::get_id()), _loggername(loggername),
              _filename(filename), _payload(payload), _payload_len(payload_len)
        {
        }
    };

    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual ~FormatItem() {}
        virtual void format(LogBuffer &buffer, const LogMsg &msg) = 0;
    };
    class MsgFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &msg) override { buffer.insert(buffer.end(), msg._payload, msg._payload + msg._payload_len); }
    };
    class LevelFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &msg) override
        {
            const char *s = LogLevel::tostring(msg._level);
            buffer.insert(buffer.end(), s, s + strlen(s));
        }
    };
    class TimeFormatItem : public FormatItem
    {
    private:
        std::string _time_fmt;

    public:
        TimeFormatItem(const std::string &fmt = "%H:%M:%S") : _time_fmt(fmt) {}
        void format(LogBuffer &buffer, const LogMsg &msg) override
        {
            struct tm t;
            localtime_r(&msg._ctime, &t);
            char tmp[128] = {0};
            size_t len = strftime(tmp, sizeof(tmp) - 1, _time_fmt.c_str(), &t);
            buffer.insert(buffer.end(), tmp, tmp + len);
        }
    };
    class FileNameFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &msg) override { buffer.insert(buffer.end(), msg._filename.begin(), msg._filename.end()); }
    };
    class LineNameFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &msg) override
        {
            char tmp[21];
            auto [p, ec] = std::to_chars(tmp, tmp + sizeof(tmp), msg._line);
            if (ec == std::errc())
                buffer.insert(buffer.end(), tmp, p);
        }
    };
    class TidNameFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &msg) override
        {
            // 使用 std::hash 将 thread::id 转换为一个可打印的数字
            // 这是最安全、最高效、无锁的方式
            size_t thread_hash = std::hash<std::thread::id>{}(msg._tid);

            char tmp[21]; // size_t on 64-bit is max 20 digits
            auto [p, ec] = std::to_chars(tmp, tmp + sizeof(tmp), thread_hash);
            if (ec == std::errc())
            {
                buffer.insert(buffer.end(), tmp, p);
            }
        }
    };
    class LoggerNameFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &msg) override { buffer.insert(buffer.end(), msg._loggername.begin(), msg._loggername.end()); }
    };
    class TabNameFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &) override { buffer.push_back('\t'); }
    };
    class NewLineNameFormatItem : public FormatItem
    {
    public:
        void format(LogBuffer &buffer, const LogMsg &) override { buffer.push_back('\n'); }
    };
    class OtherNameFormatItem : public FormatItem
    {
    private:
        std::string _str;

    public:
        OtherNameFormatItem(const std::string &s) : _str(s) {}
        void format(LogBuffer &buffer, const LogMsg &) override { buffer.insert(buffer.end(), _str.begin(), _str.end()); }
    };

    class Formatter
    {
    private:
        std::string _pattern;
        std::vector<FormatItem::ptr> _items;

    public:
        using ptr = std::shared_ptr<Formatter>;
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n") : _pattern(pattern) { assert(parsePattern()); }
        void format(LogBuffer &buffer, const LogMsg &msg)
        {
            for (auto &it : _items)
                it->format(buffer, msg);
        }

    private:
        bool parsePattern()
        {
            std::vector<std::pair<std::string, std::string>> fmt_order;
            size_t pos = 0;
            std::string key, val;
            while (pos < _pattern.size())
            {
                if (_pattern[pos] != '%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                if ((pos + 1) < _pattern.size() && _pattern[pos + 1] == '%')
                {
                    val.push_back('%');
                    pos += 2;
                    continue;
                }
                if (!val.empty())
                {
                    fmt_order.push_back({"", val});
                    val.clear();
                }
                pos++;
                if (pos == _pattern.size())
                    return false; // FIX: No cerr, just fail
                key.push_back(_pattern[pos]);
                pos++;
                if (pos < _pattern.size() && _pattern[pos] == '{')
                {
                    pos++;
                    while (pos < _pattern.size() && _pattern[pos] != '}')
                    {
                        val.push_back(_pattern[pos++]);
                    }
                    if (pos == _pattern.size())
                        return false; // FIX: No cerr, just fail
                    pos++;
                }
                fmt_order.push_back({key, val});
                key.clear();
                val.clear();
            }
            if (!val.empty())
            {
                fmt_order.push_back({"", val});
            }
            for (auto &it : fmt_order)
            {
                auto item = createItem(it.first, it.second);
                if (!item)
                    return false; // FIX: Handle creation failure
                _items.push_back(item);
            }
            return true;
        }
        FormatItem::ptr createItem(const std::string &key, const std::string &val)
        {
            if (key == "d")
                return std::make_shared<TimeFormatItem>(val);
            if (key == "t")
                return std::make_shared<TidNameFormatItem>();
            if (key == "p")
                return std::make_shared<LevelFormatItem>();
            if (key == "c")
                return std::make_shared<LoggerNameFormatItem>();
            if (key == "f")
                return std::make_shared<FileNameFormatItem>();
            if (key == "l")
                return std::make_shared<LineNameFormatItem>();
            if (key == "m")
                return std::make_shared<MsgFormatItem>();
            if (key == "n")
                return std::make_shared<NewLineNameFormatItem>();
            if (key == "T")
                return std::make_shared<TabNameFormatItem>();
            if (key == "")
                return std::make_shared<OtherNameFormatItem>(val);
            return nullptr; // FIX: Return nullptr for unknown specifiers
        }
    };

    class LogSink
    {
    public:
        using ptr = std::shared_ptr<LogSink>;
        virtual ~LogSink() {}
        virtual void Log(const char *data, size_t len) = 0;
    };
    class StdoutLogSink : public LogSink
    {
    public:
        void Log(const char *data, size_t len) override { std::cout.write(data, len); }
    };
    class FileLogSink : public LogSink
    {
    private:
        std::string _pathname;
        std::ofstream _ofs;

    public:
        FileLogSink(const std::string &pathname) : _pathname(pathname)
        {
            util::File::createDirectory(util::File::path(pathname));
            _ofs.open(_pathname, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
        void Log(const char *data, size_t len) override
        {
            _ofs.write(data, len);
            assert(_ofs.good());
        }
    };
    // ... RollLogSink can be added here if needed ...
    class RollLogSink : public LogSink
    {
    private:
        std::string _base_filename;
        size_t _max_filesize;
        std::ofstream _ofs;
        size_t _cur_filesize;

    public:
        RollLogSink(const std::string &base_filename, size_t maxsize)
            : _base_filename(base_filename), _max_filesize(maxsize), _cur_filesize(0)
        {
            std::string pathname = createNewFileName();
            util::File::createDirectory(util::File::path(pathname));
            _ofs.open(pathname, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }

        virtual void Log(const char *data, size_t len) override
        {
            if (_cur_filesize >= _max_filesize)
            {
                _ofs.close();
                std::string newpathname = createNewFileName();
                _ofs.open(newpathname, std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
                _cur_filesize = 0;
            }
            _ofs.write(data, len);
            assert(_ofs.good());
            _cur_filesize += len;
        }

    private:
        std::string createNewFileName()
        {
            time_t t = util::Date::getTime();
            struct tm lt;
            localtime_r(&t, &lt);
            std::stringstream ss;
            ss << _base_filename << "-";
            ss << lt.tm_year + 1900;
            ss << (lt.tm_mon + 1 < 10 ? "0" : "") << lt.tm_mon + 1;
            ss << (lt.tm_mday < 10 ? "0" : "") << lt.tm_mday;
            ss << "-";
            ss << (lt.tm_hour < 10 ? "0" : "") << lt.tm_hour;
            ss << (lt.tm_min < 10 ? "0" : "") << lt.tm_min;
            ss << (lt.tm_sec < 10 ? "0" : "") << lt.tm_sec;
            ss << ".log";
            return ss.str();
        }
    };

    class SinkFactory
    {
    public:
        template <typename SinkType, typename... Args>
        static LogSink::ptr create(Args &&...args) { return std::make_shared<SinkType>(std::forward<Args>(args)...); }
    };

    constexpr size_t DEFAULT_BUFFER_SIZE = 1024 * 1024 * 10;   // 10MB
    constexpr size_t THRESHOLD_BUFFER_SIZE = 1024 * 1024 * 80; // 80MB
    constexpr size_t INCREMENT_BUFFER_SIZE = 1024 * 1024 * 10; // 10MB
    class Buffer
    {
    private:
        std::vector<char> _buffer;
        size_t _reader_idx;
        size_t _writer_idx;

        void ensureEnoughSize(size_t len)
        {
            if (writeableSize() >= len)
                return;

            size_t new_size = 0;
            if (_buffer.size() < THRESHOLD_BUFFER_SIZE)
            {
                new_size = _buffer.size() * 2 + len;
            }
            else
            {
                new_size = _buffer.size() + INCREMENT_BUFFER_SIZE + len;
            }
            _buffer.resize(new_size);
        }

    public:
        Buffer()
            : _buffer(DEFAULT_BUFFER_SIZE), _reader_idx(0), _writer_idx(0)
        {
        }

        void push(const char *data, size_t len)
        {
            ensureEnoughSize(len);
            std::copy(data, data + len, &_buffer[_writer_idx]);
            shiftWriteIdx(len);
        }

        const char *readableBegin() const
        {
            return &_buffer[_reader_idx];
        }

        size_t readableSize() const
        {
            return _writer_idx - _reader_idx;
        }

        size_t writeableSize() const
        {
            return _buffer.size() - _writer_idx;
        }

        void shiftWriteIdx(size_t len)
        {
            assert(len + _writer_idx <= _buffer.size());
            _writer_idx += len;
        }

        void shiftReadIdx(size_t len)
        {
            assert(len <= readableSize());
            _reader_idx += len;
        }

        void resetBuffer()
        {
            _reader_idx = _writer_idx = 0;
        }

        void swapBuffer(Buffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_reader_idx, buffer._reader_idx);
            std::swap(_writer_idx, buffer._writer_idx);
        }

        bool empty() const
        {
            return _reader_idx == _writer_idx;
        }
    };

    enum class AsyncType
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };
    using Functor = std::function<void(Buffer &)>;
    class AsynLooper
    {
    private:
        Functor _callBack;
        AsyncType _asynctype;
        Buffer _productor_buf;
        Buffer _consumer_buf;
        std::mutex _mutex;
        std::condition_variable _pro_cond;
        std::condition_variable _con_cond;
        std::atomic<bool> _stop;
        std::thread _thread;

    public:
        using ptr = std::shared_ptr<AsynLooper>;

        AsynLooper(const Functor &callback, AsyncType asynctype = AsyncType::ASYNC_SAFE)
            : _callBack(callback),
              _asynctype(asynctype),
              _stop(false),
              _thread(std::thread(&AsynLooper::Rountine, this))
        {
        }

        ~AsynLooper()
        {
            stop();
        }

        void stop()
        {
            _stop.store(true);
            _con_cond.notify_all();
            if (_thread.joinable())
            {
                _thread.join();
            }
        }

        void push(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_asynctype == AsyncType::ASYNC_SAFE)
            {
                _pro_cond.wait(lock, [&]()
                               { return _productor_buf.writeableSize() >= len; });
            }
            _productor_buf.push(data, len);
            _con_cond.notify_one();
        }

    private:
        void Rountine()
        {
            while (!_stop.load())
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _con_cond.wait(lock, [&]()
                                   { return !_productor_buf.empty() || _stop.load(); });

                    if (_stop.load() && _productor_buf.empty())
                        break;

                    _productor_buf.swapBuffer(_consumer_buf);

                    if (_asynctype == AsyncType::ASYNC_SAFE)
                    {
                        _pro_cond.notify_all();
                    }
                } // Unlock mutex here

                _callBack(_consumer_buf);
                _consumer_buf.resetBuffer();
            }
        }
    };

    class Logger
    {
    protected:
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_value;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
        std::mutex _mutex;
        inline static thread_local LogBuffer tl_log_buffer;
        inline static thread_local std::vector<char> tl_payload_buffer;

    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &name, LogLevel::value level, Formatter::ptr fmt, const std::vector<LogSink::ptr> &sinks)
            : _logger_name(name), _limit_value(level), _formatter(fmt), _sinks(sinks) {}
        virtual ~Logger() {}
        template <typename... Args>
        void debug(const std::string &f, size_t l, const std::string &fmt, Args... args) { log_message(LogLevel::value::DEBUG, f, l, fmt, std::forward<Args>(args)...); }
        template <typename... Args>
        void info(const std::string &f, size_t l, const std::string &fmt, Args... args) { log_message(LogLevel::value::INFO, f, l, fmt, std::forward<Args>(args)...); }
        template <typename... Args>
        void warn(const std::string &f, size_t l, const std::string &fmt, Args... args) { log_message(LogLevel::value::WARN, f, l, fmt, std::forward<Args>(args)...); }
        template <typename... Args>
        void error(const std::string &f, size_t l, const std::string &fmt, Args... args) { log_message(LogLevel::value::ERROR, f, l, fmt, std::forward<Args>(args)...); }
        template <typename... Args>
        void fatal(const std::string &f, size_t l, const std::string &fmt, Args... args) { log_message(LogLevel::value::FATAL, f, l, fmt, std::forward<Args>(args)...); }
        const std::string &name() const { return _logger_name; }

    protected:
        template <typename... Args>
        void log_message(LogLevel::value level, const std::string &filename, size_t line, const std::string &fmt, Args &&...args)
        {
            if (level < _limit_value)
                return;
            int required_size = std::snprintf(nullptr, 0, fmt.c_str(), args...);
            if (required_size < 0)
                return;
            tl_payload_buffer.resize(required_size + 1);
            std::snprintf(tl_payload_buffer.data(), tl_payload_buffer.size(), fmt.c_str(), args...);
            LogMsg msg(level, line, filename, _logger_name, tl_payload_buffer.data(), required_size);
            tl_log_buffer.clear();
            _formatter->format(tl_log_buffer, msg);
            log(tl_log_buffer.data(), tl_log_buffer.size());
        }
        virtual void log(const char *data, size_t len) = 0;
    };

    class SyncLogger : public Logger
    {
    public:
        using Logger::Logger;

    protected:
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
                sink->Log(data, len);
        }
    };

    class AsyncLogger : public Logger
    {
    private:
        AsynLooper::ptr _looper;

    public:
        AsyncLogger(const std::string &name, LogLevel::value level, Formatter::ptr fmt, const std::vector<LogSink::ptr> &sinks, AsyncType type)
            : Logger(name, level, fmt, sinks),
              _looper(std::make_shared<AsynLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), type)) {}

    protected:
        void log(const char *data, size_t len) override { _looper->push(data, len); }

    private:
        void realLog(Buffer &buffer)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
                sink->Log(buffer.readableBegin(), buffer.readableSize());
        }
    };

    enum class LoggerType
    {
        SYNC_LOGGER,
        ASYNC_LOGGER
    };
    class LoggerBuilder
    {
    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        LogLevel::value _limit_value;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;

    public:
        LoggerBuilder(AsyncType default_looper_type = AsyncType::ASYNC_SAFE)
            : _looper_type(default_looper_type), _logger_type(LoggerType::SYNC_LOGGER), _limit_value(LogLevel::value::DEBUG) {}
        virtual ~LoggerBuilder() {}
        LoggerBuilder &buildEnableUnsafe()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
            return *this;
        }
        LoggerBuilder &buildLoggerType(LoggerType type)
        {
            _logger_type = type;
            return *this;
        }
        LoggerBuilder &buildLoggerName(const std::string &name)
        {
            _logger_name = name;
            return *this;
        }
        LoggerBuilder &buildLimitValue(LogLevel::value value)
        {
            _limit_value = value;
            return *this;
        }
        LoggerBuilder &buildFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
            return *this;
        }
        template <typename SinkType, typename... Args>
        LoggerBuilder &addSink(Args &&...args)
        {
            _sinks.push_back(SinkFactory::create<SinkType>(std::forward<Args>(args)...));
            return *this;
        }
        virtual Logger::ptr build() = 0;
    };
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (!_formatter)
                _formatter = std::make_shared<Formatter>();
            if (_sinks.empty())
                addSink<StdoutLogSink>();
            if (_logger_type == LoggerType::ASYNC_LOGGER)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_value, _formatter, _sinks, _looper_type);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_value, _formatter, _sinks);
        }
    };
    class LoggerManager
    {
    private:
        std::mutex _mutex;
        Logger::ptr _default_logger;
        std::unordered_map<std::string, Logger::ptr> _loggers;

        LoggerManager()
        {
            LocalLoggerBuilder builder;
            builder.buildLoggerName("default");
            _default_logger = builder.build();
            _loggers.insert(std::make_pair("default", _default_logger));
        }
        LoggerManager(const LoggerManager &) = delete;
        LoggerManager &operator=(const LoggerManager &) = delete;

    public:
        static LoggerManager &GetInstance()
        {
            static LoggerManager _inst;
            return _inst;
        }

        void addLogger(Logger::ptr logger)
        {
            if (hasLogger(logger->name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }

        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _loggers.count(name) > 0;
        }

        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
                return nullptr;
            return it->second;
        }

        Logger::ptr getDefaultLogger()
        {
            return _default_logger;
        }
    };
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        virtual Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                addSink<StdoutLogSink>();
            }
            Logger::ptr logger;

            if (_logger_type == LoggerType::ASYNC_LOGGER)
            {
                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_value, _formatter, _sinks, _looper_type);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_value, _formatter, _sinks);
            }

            LoggerManager::GetInstance().addLogger(logger);
            return logger;
        }
    };
    inline Logger::ptr getLogger(const std::string &name) { return LoggerManager::GetInstance().getLogger(name); }
    inline Logger::ptr defaultLogger() { return LoggerManager::GetInstance().getDefaultLogger(); }
}

#define LOG_LEVEL(logger, level, fmt, ...)                         \
    do                                                             \
    {                                                              \
        if (logger)                                                \
        {                                                          \
            logger->level(__FILE__, __LINE__, fmt, ##__VA_ARGS__); \
        }                                                          \
    } while (0)
#define LOG_DEBUG(logger, fmt, ...) LOG_LEVEL(logger, debug, fmt, ##__VA_ARGS__)
#define LOG_INFO(logger, fmt, ...) LOG_LEVEL(logger, info, fmt, ##__VA_ARGS__)
#define LOG_WARN(logger, fmt, ...) LOG_LEVEL(logger, warn, fmt, ##__VA_ARGS__)
#define LOG_ERROR(logger, fmt, ...) LOG_LEVEL(logger, error, fmt, ##__VA_ARGS__)
#define LOG_FATAL(logger, fmt, ...) LOG_LEVEL(logger, fatal, fmt, ##__VA_ARGS__)
#define DEBUG(fmt, ...) LOG_DEBUG(senlog::defaultLogger(), fmt, ##__VA_ARGS__)
#define INFO(fmt, ...) LOG_INFO(senlog::defaultLogger(), fmt, ##__VA_ARGS__)
#define WARN(fmt, ...) LOG_WARN(senlog::defaultLogger(), fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...) LOG_ERROR(senlog::defaultLogger(), fmt, ##__VA_ARGS__)
#define FATAL(fmt, ...) LOG_FATAL(senlog::defaultLogger(), fmt, ##__VA_ARGS__)